/*!
 * \file ModuleHelper.hpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 模块路径辅助工具
 * 
 * \details 提供跨平台的模块路径获取功能，包括：
 *          - 当前模块（DLL/SO）路径获取
 *          - 模块目录路径获取
 *          - 跨平台路径处理
 *          
 *          支持Windows和Linux两个平台，
 *          通过不同的系统API获取当前模块的完整路径，
 *          为插件系统和模块化架构提供路径支持。
 */
#pragma once
#include "../Share/StrUtil.hpp"

#ifdef _MSC_VER
#include <wtypes.h>
/*!
 * \brief Windows下的全局模块句柄
 * 
 * \details 存储当前DLL模块的句柄，
 *          在DllMain中初始化，
 *          用于后续获取模块路径。
 */
static HMODULE	g_dllModule = NULL;

/*!
 * \brief Windows DLL入口点函数
 * 
 * \details Windows系统下DLL的标准入口点，
 *          主要用于获取并保存当前DLL的模块句柄，
 *          以便后续路径查询使用。
 * 
 * \param hModule DLL模块句柄
 * \param ul_reason_for_call 调用原因（加载、卸载等）
 * \param lpReserved 保留参数
 * \return 总是返回TRUE表示初始化成功
 * 
 * \note 只在DLL_PROCESS_ATTACH时保存模块句柄
 */
BOOL APIENTRY DllMain(
	HANDLE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		g_dllModule = (HMODULE)hModule;  ///< 保存DLL模块句柄
		break;
	}
	return TRUE;
}
#else
#include <dlfcn.h>
/*!
 * \brief Linux下的辅助函数指针
 * 
 * \details 用于dladdr函数获取当前共享库路径的锚点函数，
 *          通过获取此函数的地址来定位当前模块。
 */
void inst_hlp() {}
/*!
 * \brief 获取当前模块的完整路径（Linux版本）
 * 
 * \details 使用dladdr系统调用获取当前共享库(.so)的完整路径，
 *          采用静态变量缓存结果，避免重复查询。
 * 
 * \return 返回当前模块的完整路径字符串引用
 * 
 * \note 使用Dl_info结构体和dladdr函数实现
 */
static const std::string& getInstPath()
{
	static std::string moduleName;  ///< 静态缓存的模块路径
	if (moduleName.empty())
	{
		Dl_info dl_info;
		// 获取inst_hlp函数所在模块的信息
		dladdr((void *)inst_hlp, &dl_info);
		moduleName = dl_info.dli_fname;  ///< 提取文件名（完整路径）
	}

	return moduleName;
}
#endif

/*!
 * \brief 获取当前模块所在目录的路径
 * 
 * \details 跨平台函数，获取当前模块（DLL/SO）所在的目录路径，
 *          在Windows下使用GetModuleFileName API，
 *          在Linux下使用dladdr系统调用。
 *          结果会被缓存以提高性能。
 * 
 * \return 返回模块所在目录的路径字符串（以'/'结尾）
 * 
 * \note 路径会被标准化为使用正斜杠的格式
 */
static const char* getBinDir()
{
	static std::string g_bin_dir;  ///< 静态缓存的目录路径

	if (g_bin_dir.empty())
	{
#ifdef _MSC_VER
		char strPath[MAX_PATH];
		// Windows: 获取DLL模块的完整文件路径
		GetModuleFileName(g_dllModule, strPath, MAX_PATH);

		// 标准化路径格式（转换为正斜杠）
		g_bin_dir = StrUtil::standardisePath(strPath, false);
#else
		// Linux: 获取共享库的完整文件路径
		g_bin_dir = getInstPath();
#endif
		// 提取目录部分（去除文件名）
		std::size_t nPos = g_bin_dir.find_last_of('/');
		g_bin_dir = g_bin_dir.substr(0, nPos + 1);  ///< 保留末尾的斜杠
	}

	return g_bin_dir.c_str();
}